package trackClustering.example;
import com.opencsv.CSVWriter;
import com.opencsv.exceptions.CsvValidationException;
import trackClustering.example.behavior.TrajectoryProcessByBehaviorDbacan;
import trackClustering.example.behavior.TrajectoryProcessBySpeed;
import trackClustering.example.entity.TrajectoryPoint;
import trackClustering.example.reader.TrajectoryReader;
import trackClustering.example.spatial.TrajectoryProcessorByDbscan;

import java.io.FileWriter;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

public class Main {
    public static void main(String[] args) throws IOException, CsvValidationException {
        List<TrajectoryPoint> source_points = TrajectoryReader.readTrajectoryData("src/main/resources/track250224_foshan.csv");

        // DBSCAN聚类
        Map<Integer, List<TrajectoryPoint>> spatialClusters =
                TrajectoryProcessorByDbscan.clusterPoints(source_points, -1, 3);

        // 行为分层聚类
//        TrajectoryProcessByBehaviorDbacan behaviorProcessor = new TrajectoryProcessByBehaviorDbacan(-1, 3);
//        Map<Integer, Map<Integer, List<TrajectoryPoint>>> spatialToBehaviorClusters =
//                behaviorProcessor.clusterBySpatialClusters(spatialClusters);

        // 方式1：使用K-means（自动确定k值）
        TrajectoryProcessBySpeed speedProcessor =
                new TrajectoryProcessBySpeed(
                        TrajectoryProcessBySpeed.AlgorithmType.KMEANS,
                        true,
                        -1,
                        // 无效参数（仅DBSCAN需要）
                        -1
                );
        Map<Integer, Map<Integer, List<TrajectoryPoint>>> spatialToBehaviorClusters =
                speedProcessor.clusterBySpeed(spatialClusters);

        // 输出示例格式
        for (Map.Entry<Integer, Map<Integer, List<TrajectoryPoint>>> spatialEntry : spatialToBehaviorClusters.entrySet()) {
            int spatialClusterId = spatialEntry.getKey();
            Map<Integer, List<TrajectoryPoint>> behaviorClusters = spatialEntry.getValue();

            System.out.println("空间簇" + spatialClusterId + "（原空间路线）:");
            for (Map.Entry<Integer, List<TrajectoryPoint>> behaviorEntry : behaviorClusters.entrySet()) {
                int behaviorClusterId = behaviorEntry.getKey();
                List<TrajectoryPoint> pointsInCluster = behaviorEntry.getValue();

                long minTime = pointsInCluster.stream()
                        .mapToLong(TrajectoryPoint::getTimeStamp)
                        .min()
                        .orElse(0L);
                long maxTime = pointsInCluster.stream()
                        .mapToLong(TrajectoryPoint::getTimeStamp)
                        .max()
                        .orElse(0L);
                String timeRange = formatTime(minTime) + "-" + formatTime(maxTime);

                System.out.printf("  行为簇%d（时间：%s）: 点数=%d\n",
                        behaviorClusterId, timeRange, pointsInCluster.size());
            }
            System.out.println();
        }

        // 统计信息
        int totalPointsInClusters = 0;
        for (Map<Integer, List<TrajectoryPoint>> behaviorClusters : spatialToBehaviorClusters.values()) {
            for (List<TrajectoryPoint> pointsList : behaviorClusters.values()) {
                totalPointsInClusters += pointsList.size();
            }
        }
        int noisePoints = source_points.size() - totalPointsInClusters;

        System.out.println("总点数: " + source_points.size());
        System.out.println("归类点数: " + totalPointsInClusters);
        System.out.println("噪声点数: " + noisePoints);
        System.out.println("有效簇数量: " +
                spatialToBehaviorClusters.values().stream()
                        .flatMap(m -> m.entrySet().stream())
                        .count());

        // 生成CSV
//        List<String[]> csvContent = new ArrayList<>();
//        csvContent.add(new String[]{
//                "Spatial Cluster ID", "Behavior Cluster ID", "Size", "ID", "Time",
//                "Height", "Latitude", "Longitude", "Horizontal Speed"
//        });
//        SimpleDateFormat dataFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm");
//
//        for (Map.Entry<Integer, Map<Integer, List<TrajectoryPoint>>> spatialEntry : spatialToBehaviorClusters.entrySet()) {
//            int spatialClusterId = spatialEntry.getKey();
//            Map<Integer, List<TrajectoryPoint>> behaviorClusters = spatialEntry.getValue();
//
//            for (Map.Entry<Integer, List<TrajectoryPoint>> behaviorEntry : behaviorClusters.entrySet()) {
//                int behaviorClusterId = behaviorEntry.getKey();
//                List<TrajectoryPoint> points = behaviorEntry.getValue();
//
//                for (TrajectoryPoint point : points) {
//                    try {
//                        Date time = dataFormat.parse(point.getTime());
//                        csvContent.add(new String[]{
//                                Integer.toString(spatialClusterId),
//                                Integer.toString(behaviorClusterId),
//                                Integer.toString(points.size()),
//                                point.getId(),
//                                dataFormat.format(time),
//                                Double.toString(point.getHeight()),
//                                Double.toString(point.getLatitude()),
//                                Double.toString(point.getLongitude()),
//                                Double.toString(point.getHorizontalSpeed())
//                        });
//                    } catch (ParseException e) {
//                        e.printStackTrace();
//                    }
//                }
//            }
//        }
        // 生成CSV内容部分修改为：
        List<String[]> csvContent = new ArrayList<>();
        csvContent.add(new String[]{
                "Spatial Cluster ID", "Behavior Cluster ID", "Size", "ID", "Time",
                "Height", "Latitude", "Longitude", "Horizontal Speed"
        });
        SimpleDateFormat dataFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm");
        // 1. 对空间簇ID排序
        List<Integer> spatialClusterIds = new ArrayList<>(spatialToBehaviorClusters.keySet());
        spatialClusterIds.sort(Integer::compareTo);

        for (Integer spatialClusterId : spatialClusterIds) {
            Map<Integer, List<TrajectoryPoint>> behaviorClusters = spatialToBehaviorClusters.get(spatialClusterId);

            // 2. 对行为簇ID排序
            List<Integer> behaviorClusterIds = new ArrayList<>(behaviorClusters.keySet());
            behaviorClusterIds.sort(Integer::compareTo);

            for (Integer behaviorClusterId : behaviorClusterIds) {
                List<TrajectoryPoint> points = behaviorClusters.get(behaviorClusterId);

                // 3. 对轨迹点按时间排序
                points.sort(Comparator.comparingLong(TrajectoryPoint::getTimeStamp));

                for (TrajectoryPoint point : points) {
                    try {
                        Date time = dataFormat.parse(point.getTime());
                        csvContent.add(new String[]{
                                spatialClusterId.toString(),
                                behaviorClusterId.toString(),
                                Integer.toString(points.size()),
                                point.getId(),
                                dataFormat.format(time),
                                Double.toString(point.getHeight()),
                                Double.toString(point.getLatitude()),
                                Double.toString(point.getLongitude()),
                                Double.toString(point.getHorizontalSpeed())
                        });
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        try (CSVWriter writer = new CSVWriter(new FileWriter("src/main/resources/track250224_foshan_test_out.csv"))) {
            writer.writeAll(csvContent);
        }
    }
    private static String formatTime(long timestamp) {
        Date date = new Date(timestamp);
        SimpleDateFormat formatter = new SimpleDateFormat("HH:mm");
        return formatter.format(date);
    }
}

